"""Model manager for Dingo.

Copyright (C) Sarah Mount 2008.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
"""

from __future__ import absolute_import
import wx

__author__ = 'Sarah Mount <s.mount@wlv.ac.uk>'
__date__ = 'April 2008'


class Model(object):
    """Superclass for Dingo models."""
    modeltypes = ['Radio', # TODO: Delete this in favour of ModelManager.modeltypes
                  'ADC',
                  'Energy',
                  'Time',
                  'Routing']
    def __init__(self, name, modeltype):
        self.name = name
        """@ivar: name of this model. Used in menus, etc. so B{must} be short.
        @type: str
        """
        self.modeltype = modeltype
        """@ivar: what this model is modelling!
        @constraint: C{self.modeltype in Model.modeltypes}
        @type: str
        """        
        return

class ModelManager:
    modeltypes = {'Radio':'Radio propagation model',
                  'ADC':'ADC data model',
                  'Energy':'Energy usage model',
                  'Time':'Global / local time model',
                  'Routing':'Network routing model'}
    """@cvar: Possible model types and their descriptions."""
    def __init__(self, statusbar):
        self.models = {}
        """@ivar: All available models, indexed by name (type str).
        @type: dict
        """        
        self.status = statusbar
        """@ivar: Reference to the notebook in the Dingo GUI.
        @type: wx.StatusBar
        """                        
        self.modelMenu = None
        """@ivar: Reference to the Model menu in the Dingo GUI.
        @type: wx.Menu
        """                
        self.modelMenuIds = {}
        """@ivar: Dict containing ids (indexed by name) of each model in the Models menu in the main Dingo GUI. Used to manage model submenus.
        @type: dict
        """                
        self.modelMenuSubmenus = {}
        """@ivar: Dict containing submenus for currently activated models.
        @type: dict
        """                
        # Load models
    	self._loadModels()
        return

    def _loadModels(self):
        """Load all models that can be found on disk.
	See L{Dingo.modelManager.ModelManager.modelDir}
        """
        if self.status is not None:
            self.status.SetStatusText('Model manager attempting to load models.', 1)
	from . import models
        import sys
        name = models.__name__ + '.'
        for mod in sys.modules.values():
            if mod is not None and mod.__name__.startswith(name):
            	for obj in mod.__dict__.values():
                    if isinstance(obj, Model):
                        self.models[obj.name] = obj
        return

    def getModelNames(self):
        """Return a list of the names of all available models.
        Used by the L{Dingo.Main.DingoApp} class to create model menu.
        
        @rtype: list
        """        
        return self.models.keys()

    def getAvailableModelsByType(self):
        """Return a dict containing models indexed by type.
        
        @rtype: dict
        """
        modelsbytype = {}
        for name in self.models.keys():
            if not self.models[name].modeltype in modelsbytype:
                modelsbytype[self.models[name].modeltype] = [name]
            else:
                modelsbytype[self.models[name].modeltype] = \
                	modelsbytype[self.models[name].modeltype] + [name]
        return modelsbytype

    def activateModel(self, name):
        """Activate a particular model by name.
        Called by the L{Dingo.Main.DingoApp} class.

        @type name: str
        @param name: Name of the model to activate.
        """        
    	self.status.SetStatusText('ModelManager attempting to register model: ' + name, 0)
        self.models[name].activate()
        # Deal with model menu
        menuitem = self.modelMenu.FindItemById(self.modelMenuIds[name])
        submenu =  self.models[name].createMenu()
        if submenu is not None:
            	self.status.SetStatusText('Got submenu from model' + name, 0)
        	item = self.modelMenu.AppendMenu(wx.ID_ANY, name, submenu)
                self.modelMenuSubmenus[name] = item
        else: self.modelMenuSubmenus[name] = None
        return

    def deactivateModel(self, name):
        """Deactivate a particular model by name.
        Called by the L{Dingo.Main.DingoApp} class.

        @type name: str
        @param name: Name of the model to deactivate.
        """        
        self.status.SetStatusText('ModelManager attempting to deregister model: ' + name, 0)
        self.models[name].deactivate()
        if name in self.modelMenuSubmenus and self.modelMenuSubmenus[name] is not None:
            self.status.SetStatusText('Removing submenu from model' + name, 0)
            self.modelMenu.RemoveItem(self.modelMenuSubmenus[name])
        return

    def setMenu(self, menu, menuids):
        """Called by the L{Dingo.Main.DingoApp} class to ensure the model manager has access
        to the Models menu in the main GUI.
        """
        self.modelMenu = menu
        self.modelMenuIds = menuids
        return

